package com.david;

import java.io.IOException;
import java.util.Base64;
import java.util.Collections;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.provisioning.JdbcUserDetailsManager;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository;
import org.springframework.security.web.session.HttpSessionEventPublisher;




@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true ,prePostEnabled = true)//支持基于方法级别的权限认证
public class MyConfig2 extends WebSecurityConfigurerAdapter {

	@Override
	protected void configure(HttpSecurity http) throws Exception {

		//加入前置filter，校验前端页面表单提交上来的验证码
		http.addFilterBefore(new CodeFilter(), UsernamePasswordAuthenticationFilter.class);


		http.
		// 哪些 地址需要登录
		authorizeRequests()
//		//所有请求都需要验证
//		.anyRequest().authenticated()
		//添加用户权限
//		.antMatchers("/admin/**").hasRole("admin")
//		.antMatchers("/user/**").hasRole("user")

		.and()
		.formLogin()//自带登录界面和退出界面的
		.loginPage("/login.html")
		.loginProcessingUrl("/login").permitAll()
		.failureUrl("/login.html?error")
		.defaultSuccessUrl("/ok",true).permitAll()
		.passwordParameter("oo")
		.usernameParameter("xx")
		.successHandler((httpServletRequest, httpServletResponse, authentication) -> {//在登录成功后会被调起，用于锁定资源，初始化资源等
			Object user=authentication.getPrincipal();
			System.out.println(user);
		})
		.failureHandler((httpServletRequest, httpServletResponse, e) -> e.printStackTrace())//登录失败的异常信息统计，分析失败原因，统计失败次数
		.and().logout()
		.logoutUrl("xxx")//退出之后跳转到的url
		.addLogoutHandler((httpServletRequest, httpServletResponse, authentication) -> System.out.println("退出方式1"))//退出处理器，用于清理用户资源
		.addLogoutHandler((httpServletRequest, httpServletResponse, authentication) -> System.out.println("退出方式2"))



//		.and()
//		.sessionManagement()
//		// 允许同时登录的 客户端
//		.maximumSessions(1)
//		// 已经有用户登录后， 不允许相同用户再次登录
//		.maxSessionsPreventsLogin(true)
		


		.and()
		.rememberMe()
		.and()
		.csrf().disable();
		
	}


	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {

		auth.inMemoryAuthentication()
				.withUser("111").password(new BCryptPasswordEncoder().encode("123")).roles("admin")
				.and()
				.withUser("112").password(new BCryptPasswordEncoder().encode("123")).roles("user")
				.and()
				.withUser("113").password(new BCryptPasswordEncoder().encode("123")).roles("guest")
				.and()
				.withUser("114").password(new BCryptPasswordEncoder().encode("123")).roles("admin","user");

	}

	@Bean
	RoleHierarchy roleHierarchy() {

		RoleHierarchyImpl impl = new RoleHierarchyImpl();
		impl.setHierarchy("ROLE_admin > ROLE_user");

		return impl;

	}




	//此方法是及时清理过期的session的
	@Bean
	HttpSessionEventPublisher httpSessionEventPublisher() {
	    return new HttpSessionEventPublisher();
	}


	@Bean
	PasswordEncoder passwordEncoder() {

		return new BCryptPasswordEncoder();
	}
	
	public static void main(String[] args) {

		byte[] decode = Base64.getDecoder().decode("MTIzOjE2MjM3NzAzMzY2Nzc6MmY3MjUwMTE5YTFhOTg4NTk3ZjY3YmM0ZmY1YjFlN2Q");
		//123:1623770336677:2f7250119a1a988597f67bc4ff5b1e7d
		//用户名+ 权限 + 欢乐豆 + 过期时间 + secret  = 摘要 首次登录（服务器端有 客户端没有）
		System.out.println(new String(decode));
		// 好处 不需要任何和数据源的校验
	}

}
